/*
 * cudanHostMemory.cpp
 *
 *  Created on: Dec 9, 2009
 *      Author: daniel
 */

#include "cudanHostMemory.h"

namespace CUDAN
{
	template<typename T, int D>
	HostMemory<T,D>::HostMemory() : BaseMemory<T,D>()
	{
#ifdef _DEBUG
		std::cout << "HostMemory<T,D>::HostMemory()" << std::endl;
#endif
	}

	template<typename T, int D>
	HostMemory<T,D>::HostMemory(T* copy, DimensionSizeVector& dim)
	{
#ifdef _DEBUG
		std::cout << "HostMemory<T,D>::HostMemory(T* copy, DimensionSizeVector& dim)" << std::endl;
#endif
		this->copyFrom(copy, dim);
	}

	template<typename T, int D>
	HostMemory<T,D>::HostMemory(HostMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "HostMemory<T,D>::HostMemory(HostMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	template<typename T, int D>
	HostMemory<T,D>::HostMemory(DeviceMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "HostMemory<T,D>::HostMemory(DeviceMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	template<typename T, int D>
	HostMemory<T,D>* HostMemory<T,D>::operator=(HostMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "HostMemory<T,D>* HostMemory<T,D>::operator=(HostMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	template<typename T, int D>
	HostMemory<T,D>* HostMemory<T,D>::operator=(DeviceMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "HostMemory<T,D>* HostMemory<T,D>::operator=(DeviceMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	template<typename T, int D>
	HostMemory<T,D>::~HostMemory()
	{
#ifdef _DEBUG
		std::cout << "HostMemory<T,D>::~HostMemory()" << std::endl;
#endif

	}

	template<typename T, int D>
	void HostMemory<T,D>::freeMemory()
	{
#ifdef _DEBUG
		std::cout << "void HostMemory<T,D>::freeMemory()" << std::endl;
#endif
		free(this->memory);

		this->memory = NULL;
		this->size = 0;
		this->sizeDim = DimensionSizeVector(D);
	}

	template<typename T, int D>
	void HostMemory<T,D>::freeMemoryShallow()
	{
#ifdef _DEBUG
		std::cout << "void HostMemory<T,D>::freeMemoryShallow()" << std::endl;
#endif
		this->memory = NULL;
		this->size = 0;
		this->sizeDim = DimensionSizeVector(D);
	}

	template<typename T, int D>
	void HostMemory<T,D>::print()
	{
#ifdef _DEBUG
		std::cout << "void HostMemory<T,D>::print()" << std::endl;
#endif
		DimensionSizeVector location(D);

		switch(D) {
		case 1:
			for(unsigned int i=0; i<this->sizeDim[0]; i++) {
				location[0] = i;
				this->print(location);
			}
			std::cout << std::endl;
			break;
		case 2:
			for(unsigned int i=0; i<this->sizeDim[1]; i++) {
				for(unsigned int j=0; j<this->sizeDim[0]; j++) {
					location[0] = j;
					location[1] = i;
					this->print(location);
				}
				std::cout << std::endl;
			}
			break;
		case 3:
			for(unsigned int i=0; i<this->sizeDim[2]; i++) {
				for(unsigned int j=0; j<this->sizeDim[1]; j++) {
					for(unsigned int k=0; k<this->sizeDim[0]; k++) {
						location[0] = k;
						location[1] = j;
						location[2] = i;
						this->print(location);
					}
					std::cout << std::endl;
				}
				std::cout << std::endl;
			}
			break;
		}
	}

	template<typename T, int D>
	void HostMemory<T,D>::print(DimensionSizeVector& location)
	{
#ifdef _DEBUG
		std::cout << "void HostMemory<T,D>::print(DimensionSizeVector& location)" << std::endl;
#endif
		std::cout << this->memory[this->getIndex(location)] << "\t";
	}

	template<typename T, int D>
	bool HostMemory<T,D>::allocateMemory(DimensionSizeVector& dim)
	{
#ifdef _DEBUG
		std::cout << "bool HostMemory<T,D>::allocateMemory(DimensionSizeVector& dim)" << std::endl;
#endif
		for(unsigned int i = 0; i < D; i++)
			if(dim[i] < 1) return false;

		this->sizeDim = dim;
		this->size = this->getSize(dim);

		this->memory = (T*)malloc(sizeof(T) * this->size);

		return true;
	}

	template<typename T, int D>
	bool HostMemory<T,D>::copyFrom(T* copy, DimensionSizeVector& dim)
	{
#ifdef _DEBUG
		std::cout << "bool HostMemory<T,D>::copyFrom(T* copy, DimensionSizeVector& dim)" << std::endl;
#endif
		int copysize = this->getSize(dim);

		if(this->size != copysize) {
			if(this->memory != NULL) this->freeMemory();
			this->allocateMemory(dim);
		}

		for(unsigned int i=0; i<copysize; i++) {
			this->memory[i] = copy[i];
		}

		return true;
	}

	template<typename T, int D>
	bool HostMemory<T,D>::copyFrom(HostMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool HostMemory<T,D>::copyFrom(HostMemory<T,D>* copy)" << std::endl;
#endif
		if(this->size != copy->size) {
			if(this->memory != NULL) this->freeMemory();
			this->allocateMemory(copy->sizeDim);
		}

		for(unsigned int i=0; i<copy->size; i++) {
			this->memory[i] = copy->memory[i];
		}

		return true;
	}

	template<typename T, int D>
	bool HostMemory<T,D>::copyFrom(DeviceMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool HostMemory<T,D>::copyFrom(DeviceMemory<T,D>* copy)" << std::endl;
#endif
		return copy->copyTo(this);
	}

	template<typename T, int D>
	bool HostMemory<T,D>::copyFromShallow(T* copy, DimensionSizeVector& dim)
	{
#ifdef _DEBUG
		std::cout << "bool HostMemory<T,D>::copyFromShallow(T* copy, DimensionSizeVector& dim)" << std::endl;
#endif
		int copysize = this->getSize(dim);

		if(this->size != copysize) {
			if(this->memory != NULL) this->freeMemory();
			this->allocateMemory(dim);
		}

		this->memory = copy;

		return true;
	}

	template<typename T, int D>
	bool HostMemory<T,D>::copyFromShallow(HostMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool HostMemory<T,D>::copyFromShallow(HostMemory<T,D>* copy)" << std::endl;
#endif
		if(this->size != copy->size) {
			if(this->memory != NULL) this->freeMemory();
			this->allocateMemory(copy->sizeDim);
		}

		this->memory = copy->memory;

		return true;
	}

	template<typename T, int D>
	bool HostMemory<T,D>::copyTo(T* copy, DimensionSizeVector& dim)
	{
#ifdef _DEBUG
		std::cout << "bool HostMemory<T,D>::copyTo(T* copy, DimensionSizeVector& dim)" << std::endl;
#endif
		int copysize = this->getSize(dim);

		if(this->size != copysize) return false;

		for(unsigned int i=0; i<copysize; i++) {
			copy[i] = this->memory[i];
		}

		return true;
	}

	template<typename T, int D>
	bool HostMemory<T,D>::copyTo(HostMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool HostMemory<T,D>::copyTo(HostMemory<T,D>* copy)" << std::endl;
#endif
		if(this->size != copy->size) {
			if(copy->memory != NULL) copy->freeMemory();
			copy->allocateMemory(this->sizeDim);
		}

		copy->memory = this->memory;

		return true;
	}

	template<typename T, int D>
	bool HostMemory<T,D>::copyTo(DeviceMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool HostMemory<T,D>::copyTo(DeviceMemory<T,D>* copy)" << std::endl;
#endif
		return copy->copyFrom(this);
	}
}
